#include "chat_servlet.h"
#include "protocol.h"
#include "../src/log.h"
#include "../src/lock.h"


namespace chat
{
    static johnsonli::Logger::ptr g_logger = LOG_NAME("system");

    johnsonli::RWMutex m_mutex;

    // name -> session
    static std::map<std::string, johnsonli::http::WSSession::ptr> m_sessions;

    bool is_session_exists(const std::string& id)
    {
        johnsonli::RWMutex::ReadLock lock(m_mutex);
        auto it = m_sessions.find(id);
        return it != m_sessions.end();
    }

    uint32_t SendMessage(johnsonli::http::WSSession::ptr session, ChatMessage::ptr msg)
    {
        return !session->sendMessage(msg->toString());
    }

    void session_notify(ChatMessage::ptr msg, johnsonli::http::WSSession::ptr session = nullptr)
    {
        johnsonli::RWMutex::WriteLock lock(m_mutex);
        auto sessions = m_sessions; // 赋值一份，这样就不会在发送的时候锁住，能够处理其他请求
        lock.unlock();

        for(auto& i : sessions) 
        {   
            // 自己不发
            if(i.second == session) continue;
            SendMessage(i.second, msg);
        }
    }

    ChatServlet::ChatServlet()
        : WSServlet("ChatServlet")
    {}

    ChatServlet::~ChatServlet(){}

    int32_t ChatServlet::onConnect(johnsonli::http::HttpRequest::ptr header
                            ,johnsonli::http::WSSession::ptr session)
    {
        LOG_INFO(g_logger) << "onConnect";
        return 0;
    }

    int32_t ChatServlet::onClose(johnsonli::http::HttpRequest::ptr header
                            ,johnsonli::http::WSSession::ptr session)
    {
        auto name = header->getHeader("$id");     
    
        if(!name.empty())
        {
            LOG_INFO(g_logger) << "onClose id=" << name;
            ChatMessage::ptr nty(new ChatMessage);
            nty->set("type", "user_leave");
            nty->set("time", johnsonli::Time2Str());
            nty->set("name", header->getHeader("$id"));
            session_notify(nty, session);

            m_sessions.erase(name);
        }
                  
        LOG_INFO(g_logger) << "onClose";
        return 0;
    }

    int32_t ChatServlet::handle(johnsonli::http::HttpRequest::ptr header
                        ,johnsonli::http::WSFrameMessage::ptr msgx
                        ,johnsonli::http::WSSession::ptr session)
    {
        // LOG_INFO(g_logger) << "handle";
        LOG_INFO(g_logger) << "handle" << "-" << session << "-" << msgx->getData();

        auto msg = ChatMessage::Create(msgx->getData());
        auto id = header->getHeader("$id");
        // 解析失败
        if(!msg)
        {
            return 1;
        }
        
        /*
        协议
        登录请求：{type:"login_request", name:"xxx"}
        登录响应：{type:"login_response", result="400", msg:"name is null"}

        发送请求：{type:"send_request", msg:"hello"}
        发送响应：{type:"send_response", result="200", msg:"ok"}

        用户进入响应：{type:"user_enter", time:"2022-03-23 12:00:00", name:"xxx"}
        消息广播响应：{type:"msg", time:"2022-03-23 12:00:00", name:"xxx", msg:"msg"}
        */
        ChatMessage::ptr rsp(new ChatMessage);
        const std::string& type = msg->get("type");
        // 登录请求
        if(type == "login_request")
        {
            rsp->set("type", "login_response");
            auto name = msg->get("name");
            if(name.empty())    // 名字不能为null
            {
                rsp->set("result", "400");
                rsp->set("msg", "name is null");
                SendMessage(session, rsp);
                return 1;
            }
        
            if(is_session_exists(name))     // 登录过了
            {
                rsp->set("result", "401");
                rsp->set("msg", "logined");
                SendMessage(session, rsp);
                return 1;
            }

            rsp->set("result", "200");
            rsp->set("msg", "ok");

            header->setHeader("$id", name); // 将name存下来
            m_sessions[name] = session;     // 放到聊天室

            // 通知
            ChatMessage::ptr nty(new ChatMessage);
            nty->set("type", "user_enter");
            nty->set("time", johnsonli::Time2Str());
            nty->set("name", name);
            session_notify(nty, session);

            return SendMessage(session, rsp);
        }
        else if(type == "send_request") // 发送请求
        {
            rsp->set("type", "send_response");
            auto m = msg->get("msg");
            if(m.empty())   // 消息不能为null
            {
                rsp->set("result", "500");
                rsp->set("msg", "msg is null");
                return SendMessage(session, rsp);
            }
            rsp->set("result", "200");
            rsp->set("msg", "ok");

            ChatMessage::ptr nty(new ChatMessage);
            nty->set("type", "msg");
            nty->set("time", johnsonli::Time2Str());
            nty->set("name", header->getHeader("$id"));
            nty->set("msg", m);
            session_notify(nty, nullptr);
            
            return SendMessage(session, rsp);
        }
        else
        {}
        return 0;
    }

}